/*
 * Copyright 2019-2025 the original author or authors.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * https://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.iiifi.kite.alarm.listener;

import java.util.Objects;

import org.apache.rocketmq.client.exception.MQClientException;
import org.apache.rocketmq.client.producer.DefaultMQProducer;
import org.apache.rocketmq.common.message.Message;
import org.apache.rocketmq.remoting.exception.RemotingException;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.cloud.commons.util.InetUtils;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.event.EventListener;
import org.springframework.core.env.Environment;
import org.springframework.core.env.EnvironmentCapable;
import org.springframework.lang.Nullable;
import org.springframework.scheduling.annotation.Async;

import com.iiifi.kite.alarm.callback.AlarmSendCallback;
import com.iiifi.kite.alarm.configuration.KiteAlarmAutoConfiguration;
import com.iiifi.kite.alarm.event.KiteErrorEvent;
import com.iiifi.kite.alarm.properties.KiteAlarmProperties;
import com.iiifi.kite.core.spring.SpringContextUtils;
import com.iiifi.kite.rocketmq.core.MessageBuilder;

import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;

/**
 * kite 异常监听
 *
 * @author kite@iiifi.com 花朝
 */
@Slf4j
@Configuration
@AllArgsConstructor
@AutoConfigureAfter(KiteAlarmAutoConfiguration.class)
@ConditionalOnProperty(value = "kite.error.notify.enabled", havingValue = "true", matchIfMissing = true)
public class KiteErrorEventListener implements EnvironmentAware, EnvironmentCapable {

    @Nullable
    private Environment environment;
    private final InetUtils inetUtils;
    private final ServerProperties properties;
    private final KiteAlarmProperties kiteExceptionProperties;

    @Async
    @EventListener(KiteErrorEvent.class)
    public void handleError(KiteErrorEvent event) {
        log.info("[Error Event] Listen to the [KiteErrorEvent] exception: {}", event.getExceptionName());
        // 设置 remoteHost 触发的服务 host 和 ip 信息
        InetUtils.HostInfo hostInfo = inetUtils.findFirstNonLoopbackHostInfo();
        String hostname = hostInfo.getHostname();
        String ipAddress = hostInfo.getIpAddress();
        int port = properties.getPort();
        // 规则 hostname[ip:port]
        if (hostname.equals(ipAddress)) {
            event.setRemoteHost(String.format("%s:%d", hostname, port));
        } else {
            event.setRemoteHost(String.format("%s[%s:%d]", hostname, ipAddress, port));
        }
        Objects.requireNonNull(environment, "Spring boot 环境下 Environment 不可能为null。");
        String appName = environment.getProperty("spring.application.name", "");
        String env = environment.getProperty("kite.env");
        // 应用名
        event.setAppName(appName);
        // 环境
        event.setEnv(env);
        // 发送 异步 事件
        Message message = MessageBuilder.of(event)
                .topic(kiteExceptionProperties.getTopic())
                .build();
        try {
            DefaultMQProducer producer = SpringContextUtils.getBean(DefaultMQProducer.class);
            if (producer != null) {
                producer.send(message, new AlarmSendCallback());
            }
            // todo 待支持http请求方式发生
        } catch (MQClientException | RemotingException | InterruptedException e) {
            log.error("发送异常消息失败，" + e.getMessage(), e);
        }
    }

    @Override
    public void setEnvironment(Environment environment) {
        this.environment = environment;
    }

    @Override
    public Environment getEnvironment() {
        Objects.requireNonNull(environment, "Spring boot 环境下 Environment 不可能为null。");
        return this.environment;
    }
}
